# -*- coding:utf-8 -*-

__author__ = 'zhaoxp'


import json


class ToDictMixin(object):

    def to_dict(self):
        return self._traverse_dict(self.__dict__)

    def _traverse_dict(self, instance_dict):
        output = {}
        for key, value in instance_dict.items():
            #print('key = %s, value = %s'%(key,value))
            output[key] = self._traverse(key, value)
        return output

    def _traverse(self, key, value):
        if isinstance(value, ToDictMixin):
            return value.to_dict()
        elif isinstance(value, dict):
            return self._traverse_dict(value)
        elif isinstance(value, list):
            return [self._traverse(key, i) for i in value]
        elif hasattr(value, '__dict__'):
            return self._traverse_dict(value.__dict__)
        elif value is None:
            return 'null'
        else:
            return value


class BinaryTree(ToDictMixin):

    def __init__(self, value, left=None, right=None):
        self.value = value
        self.left = left
        self.right = right


class BinaryTreeWithParent(BinaryTree):

    def __init__(self, value, left=None, right=None, parent=None):
        super(BinaryTreeWithParent, self).__init__(value, left, right)
        self.parent = parent

    def _traverse(self, key, value):
        # print key,value
        if isinstance(value, BinaryTreeWithParent) and key == 'parent':
            return value.value
        else:
            return super(BinaryTreeWithParent, self)._traverse(key, value)


class NamedSubTree(ToDictMixin):

    def __init__(self, name, tree_with_parent):
        self.name = name
        self.tree_with_parent = tree_with_parent


class JsonMixin(object):
    @classmethod
    def from_json(cls, data):
        print('data = %s' % data)
        kwargs = json.loads(data)
        print('kwargs = %s' % kwargs)
        return cls(**kwargs)

    def to_json(self):
        return json.dumps(self.to_dict())


class Machine(object):
    #def __init__(self, cores, ram, disk):
    def __init__(self, cores=None, ram=None, disk=None):
        self.cores = cores
        self.ram = ram
        self.disk = disk


class DatacenterRack(ToDictMixin, JsonMixin):

    def __init__(self, switch=None, machines=None):
        self.switch = switch
        self.machines = [Machine(**kwargs) for kwargs in machines]


def test1():
    tree = BinaryTree(10, left=BinaryTree(7, right=BinaryTree(9)),
                      right=BinaryTree(13, left=BinaryTree(11)))
    print(str(tree.to_dict()).replace('\'', '\"'))


def test2():
    root = BinaryTreeWithParent(10)
    root.left = BinaryTreeWithParent(7, parent=root)
    root.left.right = BinaryTreeWithParent(9, parent=root.left)
    print(str(root.to_dict()).replace('\'', '\"'))


def test3():
    root = BinaryTreeWithParent(10)
    root.left = BinaryTreeWithParent(7, parent=root)
    root.left.right = BinaryTreeWithParent(9, parent=root.left)
    my_tree = NamedSubTree('foobar', root.left.right)
    print(str(my_tree.to_dict()).replace('\'', '\"'))


serialized = """{
"switch":{"pports":5,"speed":1e9},
"machines":[
    {"cores":8,"ram":32e9,"disk":5e12},
    {"cores":4,"ram":16e9,"disk":1e12},
    {"cores":2,"ram":4e9,"disk":500e9}
]
}"""


def test4():
    deserialized = DatacenterRack.from_json(serialized)
    print('deserialized = %s' % deserialized)
    roundtrip = deserialized.to_json()
    print('roundtrip = %s' % roundtrip)
    print json.loads(serialized) == json.loads(roundtrip)


if __name__ == '__main__':
    # test1()
    # test2()
    # test3()
    test4()
